<!--------------------------------------------------------------------------->
<!--                           INTRODUCTION                                

 The Code Project article submission template (HTML version)

Using this template will help us post your article sooner. To use, just 
follow the 3 easy steps below:
 
     1. Fill in the article description details
     2. Add links to your images and downloads
     3. Include the main article text

That's all there is to it! All formatting will be done by our submission
scripts and style sheets. 

-->
<!--------------------------------------------------------------------------->
<!--                        IGNORE THIS SECTION                            -->
<html>
<head>
 <title>The Code Project</title>
 <style>
  BODY, P, TD
  {
   font-family: Verdana, Arial, Helvetica, sans-serif;
   font-size: 10pt;
  }
  H2, H3, H4, H5
  {
   color: #ff9900;
   font-weight: bold;
  }
  H2
  {
   font-size: 13pt;
  }
  H3
  {
   font-size: 12pt;
  }
  H4
  {
   font-size: 10pt;
   color: black;
  }
  PRE
  {
   background-color: #FBEDBB;
   font-family: "Courier New" , Courier, mono;
   white-space: pre;
  }
  CODE
  {
   color: #990000;
   font-family: "Courier New" , Courier, mono;
  }
 </style>
 <link rel="stylesheet" type="text/css" href="http://www.codeproject.com/styles/global.css">
</head>
<body bgcolor="#FFFFFF" color="#000000">
 <!--------------------------------------------------------------------------->
 <!-------------------------------     STEP 1      --------------------------->
 <!--  Fill in the details (CodeProject will reformat this section for you) -->
 <pre lang="cs">Title:       Automating VMWare Tasks in C# with VIX API
Author:      Daniel Doubrovkine
Email:       dblock@dblock.org
Member ID:   913212
Language:    C#
Platform:    Windows, VMWare
Technology:  C#, COM
Level:       Intermediate
Description: A VMWare tasks library and primer
Section      Suggest a section...
SubSection   Suggest a subsection...
License:     MIT
</pre>
 <ul class="download">
  <li><a href="Vestris.VMWareTasks.zip">Download binaries &amp; source - 25 Kb</a></li>
 </ul>
 <p>
  <img src="VMWareLogo.jpg" alt="VMWare" width="160" height="63"></p>
 <!-------------------------------     STEP 3      --------------------------->
 <!--  Add the article text. Please use simple formatting (<h2>, <p> etc)   -->
 <h2>
  Introduction
 </h2>
 <p>
  I've been playing with <a href="http://www.vmware.com/">VMware</a> lately, both
  Workstation and VMware Infrastructure (VI). The company has really stepped up with
  the new SDKs and the level of programmable interfaces, making some excellent implementation
  decisions that enable developers to drive virtual machines programmatically with
  an asynchronous, job-based programming model. Unfortunately that turns out to be
  too complicated for 99.9% of scenarios and most developers want to use a simple
  object-oriented interface for common VMWare tasks. The VMWareTasks library implements
  that interface and makes programming against virtual machine a no brainer. This
  article explains how to use the library and discusses some of its implementation
  details.</p>
 <h2>
  Background
 </h2>
 <p>
  There're two types of VMWare APIs.</p>
 <ul>
  <li>VMWare Virtual Infrastructure SDK: a set of tools and APIs to manage a VMWare
   Infrastructure environment. A toolkit has also been released that contains managed
   wrappers on top of the SOAP interface provided by a VMWare deployment. It's focused
   on VMWare ESX or VirtualCenter management and is beyond the scope of this article.
  </li>
  <li>VMWare VIX API. The VIX API allows developers to write programs and scripts that
   automate virtual machine operations, as well as the guests within virtual machines.
   It runs on both Windows and Linux and supports management of VMware Server, Workstation,
   and Virtual Infrastructure (both ESX and vCenter). Bindings are provided for C,
   Perl, and COM (Visual Basic, VBscript, C#). In this post I'll focus on the C# implementation.
  </li>
 </ul>
 <h2>
  Using the Library</h2>
 <p>
  In order to use the library or build or run the source code you must install the
  following VMWare software.
 </p>
 <ul>
  <li>VMWare VIX. This is the SDK, obtained from <a href="http://www.vmware.com/download/sdk/vmauto.html">
   http://www.vmware.com/download/sdk/vmauto.html</a>. The new 1.6.2 version is required
   for VI support.</li>
  <li>Either VMWare Workstation 6.5.2, a VI environment (I use ESX), or both.</li>
 </ul>
 <p>
  In your project add a reference to <code>Vestris.VMWareLib.dll</code> and a namespace
  reference.
 </p>
 <pre lang="cs">using Vestris.VMWareLib;</pre>
 <p>
  You can now connect to a local VMWare Workstation or a remote ESX server and perform
  VMWare tasks. Here's an example that creates, restores, powers on and removes a
  snapshot on a VMWare Workstation.
 </p>
 <pre lang="cs">
// declare a virtual host
VMWareVirtualHost virtualHost = new VMWareVirtualHost();
// connect to a local (VMWare Workstation) virtual machine
virtualHost.ConnectToVMWareWorkstation();
// open an existing virtual machine
VMWareVirtualMachine virtualMachine = virtualHost.Open("C:\Virtual Machines\xp\xp.vmx");
// power on this virtual machine
virtualMachine.PowerOn();
// wait for tools to launch
virtualMachine.WaitForToolsInGuest();
// login to the virtual machine
virtualMachine.LoginInGuest("Administrator", "password");
// run notepad
virtualMachine.RunProgramInGuest("notepad.exe", string.Empty);
// create a new snapshot
string name = "New Snapshot";
// take a snapshot at the current state
virtualMachine.Snapshots.CreateSnapshot(name, "test snapshot");
// power off
virtualMachine.PowerOff();
// find the newly created snapshot
VMWareSnapshot snapshot = virtualMachine.Snapshots.GetNamedSnapshot(name);
// revert to the new snapshot
snapshot.RevertToSnapshot();
// delete snapshot
snapshot.RemoveSnapshot();</pre>
 <h2>
  Implementation
 </h2>
 <p>
  The following sections describe VMWareTasks library implementation details. It's
  absolutely not necessary to understand those in order to use the library.</p>
 <h3>
  Connecting to VMWare in pure VIX API
 </h3>
 <p>
  Connecting synchronously to either a local VMWare Workstation or an ESX server is
  virtually identical. The ESX server requires an URL to the SOAP SDK (eg. https://esxserver/sdk)
  and a username and password.
 </p>
 <pre lang="cs">public IHost ConnectToVMWareWorkstation()
{
    return Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_WORKSTATION, string.Empty, 0, string.Empty, string.Empty);
}

public IHost ConnectToVMWareVIServer(string hostName, int hostPort, string username, string password)
{
    return Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,  hostName, hostPort, username, password);
}

public IHost Connect(int hostType, string hostName, int hostPort, string username, string password)
{
    VixLib vix = new VixLib();
    IJob vmJob = vix.Connect(Constants.VIX_API_VERSION, hostType, hostName, hostPort, username, password, 0, null, null);
    // You need to get the IHost object that represents the host where your VM is located. 
    // Since COM allocates the object you need to use this funky mechanism to extract the IHosts array.
    object[] properties = { Constants.VIX_PROPERTY_JOB_RESULT_HANDLE };
    // Wait for the operation to complete
    object hosts = VmwareVixInterop.Wait(vmJob, properties);
    object[] hostArray = hosts as object[];
    return (IHost) hostArray[0];
}
  </pre>
 <p>
  You have to declare an array of properties that you want the job to produce, start
  a VMWare job and examine the results for the host handle. You can see how cumbersome
  this is! The API was originally designed for C, then extended to COM with a very
  limited object model: a number of interfaces were declared, but no corresponding
  COM classes have been implemented. Also, because the job interface is generic, there're
  no strongly typed results.
 </p>
 <p>
  We can easily fill this gap in our C# implementation.
 </p>
 <h3>
  Transforming Error Codes into Exceptions
 </h3>
 <p>
  The first task for wrapping any API is to implement error handling. Our managed
  implementation must translate error codes into managed exceptions. VIX API provides
  an implementation for the IVixLib interface which contains a couple of helper methods
  (very C-programmer). We'll be interested in <code>IVixLib.ErrorIndicatesFailure</code>
  and <code>IVixLib.GetErrorText</code> combined with a new class, <code>VMWareException</code>.
 </p>
 <pre lang="cs">public abstract class VMWareInterop
{
    public static VixLib Instance = new VixLib();

    public static void Check(ulong errCode)
    {
        if (Instance.ErrorIndicatesFailure(errCode))
        {
            throw new VMWareException(errCode);
        }
    }
}  </pre>
 <p>
  Aside from the abstract <code>VMWareInterop</code> our goal is to produce concrete
  classes that wrap various aspects of VMWare functionality.
 </p>
 <h3>
  Base VMWareVixHandle
 </h3>
 <p>
  VMWare COM API returns interface pointers such as <span style="color: #990000; font-family: Courier New">
   ISnapshot</span>. The objects also implement <span style="color: #990000; font-family: Courier New">
    IVixHandle</span> which gives access to a set of object properties. We will base-class
  everything on <span style="color: #990000; font-family: Courier New">VMWareVixHandle</span>.
 </p>
 <pre lang="cs">public class VMWareVixHandle&lt;T&gt;
{
    protected T _handle = default(T);
    
    protected IVixHandle _vixhandle
    {
        get
        {
            return (IVixHandle) _handle;
        }
    }

    public VMWareVixHandle()
    {

    }

    public VMWareVixHandle(T handle)
    {
        _handle = handle;
    }
    
    public object[] GetProperties(object[] properties)
    {
        object result = null;
        VMWareInterop.Check(_vixhandle.GetProperties(properties, ref result));
        return (object[]) result;
    }

    public R GetProperty&lt;R&gt;(int propertyId)
    {
        object[] properties = { propertyId };
        return (R) GetProperties(properties)[0];
    }
}
  </pre>
 <h3>
  Implementing VMWareJob
 </h3>
 <p>
  Since all operations in VMWare are job-based, let's wrap up a job. If we use the
  COM API directly we would have to call <code>IVixLib.Wait</code> passing a job handle.
  In an object-oriented library this operation belongs inside the job, plus a job
  is also a a <code>VMWareVixHandle</code>.
 </p>
 <pre lang="cs"> public class VMWareJob : VMWareVixHandle&lt;IJob&gt;
 {
     public VMWareJob(IJob job)
         : base(job)
     {
     
     }

     public void Wait()
     {
         VMWareInterop.Check(_handle.WaitWithoutResults());
     }
 }
  </pre>
 <p>
  One very common problem in VMWare API implementations that transform a asynchronous
  job into a synchronous one is to use the blocking wait above. This is a bad design
  decision since this call may never return. VMWare server may timeout or someone
  can pull the network cable, leaving your program hanging. I originally wrote a busy
  wait where all externally visible wait functions were based on the following <code>
   InternalWait</code>.
 </p>
 <pre lang="cs">private void InternalWait(int timeoutInSeconds)
{
    if (timeoutInSeconds == 0)
    {
        throw new ArgumentOutOfRangeException("timeoutInSeconds");
    }

    // active wait for the job to finish
    bool isComplete = false;
    while (!isComplete && timeoutInSeconds > 0)
    {
        VMWareInterop.Check(_handle.CheckCompletion(out isComplete));
        if (isComplete) break;
        Thread.Sleep(1000);
        timeoutInSeconds--;
    }

    if (timeoutInSeconds == 0)
    {
        throw new TimeoutException();
    }
}
</pre>
 <p>
  A more elegant implementation combines a callback mechanism provided by VixCOM with
  every asynchronous API and a blocking wait with a timeout. Wait is now signaled
  and there's no CPU spin waiting for completion of an asynchronous API call.
 </p>
 <pre lang="cs">public class VMWareJobCallback : ICallback
{
    #region ICallback Members

    private EventWaitHandle _jobCompleted = new EventWaitHandle(
         false, EventResetMode.ManualReset);

    public void OnVixEvent(IJob job, int eventType, IVixHandle moreEventInfo)
    {
        switch (eventType)
        {
            case VixCOM.Constants.VIX_EVENTTYPE_JOB_COMPLETED:
                _jobCompleted.Set();
                break;
        }
    }

    public bool TryWaitForCompletion(int timeoutInMilliseconds)
    {
        return _jobCompleted.WaitOne(timeoutInMilliseconds, false);
    }

    public void WaitForCompletion(int timeoutInMilliseconds)
    {
        if (!TryWaitForCompletion(timeoutInMilliseconds))
        {
            throw new TimeoutException();
        }
    }

    #endregion
}  
 </pre>
 <p>
  This and some generic code in <code>VMWareJob</code> can now be used inside <code>
   Connect</code>. I have modified <code>VMWareJob</code> to require a <code>VMWareCallback</code>
  in order to prevent callers from ever having a blocking wait.
 </p>
 <pre lang="cs">VMWareJobCallback callback = new VMWareJobCallback();
VMWareJob job = new VMWareJob(VMWareInterop.Instance.Connect(
    Constants.VIX_API_VERSION, Constants.VIX_SERVICEPROVIDER_VMWARE_SERVER, hostName, hostPort,
    username, password, 0, null, callback), callback); </pre>
 <h3>
  VMWareVirtualHost
 </h3>
 <p>
  With <code>VMWareJob</code> and <code>VMWareException</code> it's now possible to
  implement <code>VMWareVirtualHost</code> and connect to it. Note references to default
  timeouts (a collection of constants) and some facilities in <code>VMWareJob</code>
  that add strong typing into VMWare job results.
 </p>
 <pre lang="cs">public class VMWareVirtualHost
{
    private IHost _host = null;

    public VMWareVirtualHost()
    {

    }

    public void ConnectToVMWareWorkstation()
    {
        ConnectToVMWareWorkstation(VMWareInterop.Timeouts.ConnectTimeout);
    }

    public void ConnectToVMWareWorkstation(int timeoutInSeconds)
    {
        Connect(Constants.VIX_SERVICEPROVIDER_VMWARE_WORKSTATION,
            string.Empty, 0, string.Empty, string.Empty, timeoutInSeconds);
    }

    private void Connect(int hostType, string hostName, int hostPort, string username, string password, int timeout)
    {
        int serviceProvider = (int)serviceProviderType;
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(VMWareInterop.Instance.Connect(
            Constants.VIX_API_VERSION, serviceProvider, hostName, hostPort,
            username, password, 0, null, callback), callback);

        _handle = job.Wait&lt;IHost&gt;(Constants.VIX_PROPERTY_JOB_RESULT_HANDLE, timeout);
        _serviceProviderType = serviceProviderType;
    }
}        
  </pre>
 <p>
  <code>VMWareVirtualHost</code> can now implement opening of an actual virtual machine
  and return an instance of <code>VMWareVirtualMachine</code>.
 </p>
 <pre lang="cs">public VMWareVirtualMachine Open(string fileName, int timeoutInSeconds)
{
    VMWareJobCallback callback = new VMWareJobCallback();
    VMWareJob job = new VMWareJob(_handle.OpenVM(fileName, callback), callback);
    return new VMWareVirtualMachine(job.Wait
<ivm2>(
        Constants.VIX_PROPERTY_JOB_RESULT_HANDLE,
        timeoutInSeconds));
}
  </pre>
 <p>
  Based on this model we can code many functions of <code>VMWareVirtualMachine</code>,
  <code>VMWareSnapshot</code>, etc. The rest is implementation details.
 </p>
 <p>
  <img src="VMWareClasses.jpg">
 </p>
 <h2>
  Advanced Implementation Details
 </h2>
 <h3>
  Yielding Property Arrays
 </h3>
 <p>
  One of the peculiar VIX COM API constructs is the combination that returns arrays
  of properties. This is done with two functions: <code>GetNumProperties</code> and
  <code>GetNthProperties</code>. The first returns the number of property arrays returned
  by the job and the second fetches a property array at a given index. The first obvious
  step is to wrap the functions within the job class.
 </p>
 <pre lang="cs">public T GetNthProperties&lt;T&gt;(int index, object[] properties)
{
    object result = null;
    VMWareInterop.Check(_handle.GetNthProperties(index, properties, ref result));
    return (T) result;
}

public int GetNumProperties(int property)
{
    return _handle.GetNumProperties(property);
}
  </pre>
 <p>
  We can now write such properties as <code>RunningVirtualMachines</code>.
 </p>
 <pre lang="cs">public IEnumerable&lt;VMWareVirtualMachine&gt; RunningVirtualMachines
{
    get
    {    
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(_handle.FindItems(
            Constants.VIX_FIND_RUNNING_VMS, null, -1, callback), 
            callback);
        object[] properties = { Constants.VIX_PROPERTY_FOUND_ITEM_LOCATION };
        for (int i = 0; i &lt; job.GetNumProperties((int) properties[0]); i++)
        {
            yield return this.Open(
                (string) job.GetNthProperties&lt;object[]&gt;(i, properties)[0]);
        }
    }
}
  </pre>
 <p>
  This is nice, but still not good enough. Let's combine the number of results and
  the results themselves in a <code>YieldWait</code> method.
 </p>
 <pre lang="cs">
public IEnumerable &lt;object[]&gt; YieldWait(object[] properties, int timeoutInSeconds)
{
    Wait(timeoutInSeconds);
    for (int i = 0; i < GetNumProperties((int)properties[0]); i++)
    {
        yield return GetNthProperties&lt;object[]&gt;(i, properties);
    }
}
  </pre>
 <p>
  This results in a nice improvement over the previous implementation.
 </p>
 <pre lang="cs">public IEnumerable&lt;VMWareVirtualMachine&gt; RunningVirtualMachines
{
    get
    {
        VMWareJobCallback callback = new VMWareJobCallback();
        VMWareJob job = new VMWareJob(_handle.FindItems(
            Constants.VIX_FIND_RUNNING_VMS, null, -1, callback), 
            callback);
        foreach (object[] runningVirtualMachine in job.YieldWait(properties, VMWareInterop.Timeouts.FindItemsTimeout))
        {
            yield return this.Open((string) runningVirtualMachine[0]);
        }
    }
}  </pre>
 <h3>
  Dates and Times
 </h3>
 <p>
  Date/time in VMWare VIX is expressed in UNIX EPOCH (number of seconds since January
  1st, 1970).
 </p>
 <pre lang="cs">DateTime currentDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds((long) dt);</pre>
 <h2>
  Source Code and Patches
 </h2>
 <p>
  This project lives on CodePlex at <a href="http://www.codeplex.com/vmwaretasks">http://www.codeplex.com/vmwaretasks</a>.
  You can find the latest information about this library at <a href="http://code.dblock.org">
   code.dblock.org</a>. You&#39;re encouraged to submit patches for added functionality
  and bug fixes.</p>
 <h2>
  History
 </h2>
 <ul>
  <li>12/22/2008: Initial article, version 1.0.</li>
  <li>02/11/2009: revised &quot;Using VMWareTasks&quot; and described implementation
   of a blocking job wait</li></li>
  <li>02/12/2009: moved to CodePlex, version 1.1</li>
 </ul>
 <h2>
  License</h2>
 <p>
  This library, along with any associated source code and files, is published under
  the MIT license./p>
  <!-------------------------------    That's it!   --------------------------->
 </li>
</body>
</html>
